package com.novoda.runbuddy.controller;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import android.content.Context;
import android.graphics.BitmapFactory;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;

import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.GeoPoint;
import com.novoda.runbuddy.R;
import com.novoda.runbuddy.activity.CurrentRunMap;
import com.novoda.runbuddy.model.Jog;
import com.novoda.runbuddy.provider.ActivityID;
import com.novoda.runbuddy.service.IRemoteStopClockService;
import com.novoda.runbuddy.service.RemoteStopClockServiceInterface;
import com.novoda.runbuddy.util.DBHelperImpl;
import com.novoda.runbuddy.util.IDBHelper;
import com.novoda.runbuddy.view.CurrentRunMapView;
import com.novoda.runbuddy.view.overlay.CurrentRunMapOverlay;
import com.novoda.runbuddy.view.overlay.DetailsOverlay;

public class CurrentRunMapControllerImpl implements ICurrentRunMapController {

	public CurrentRunMapView			mapOfJogView;
	private MapController				mapViewController;
	private CurrentRunMap				mapOfJogActivity;
	private MyLocationOverlay			overlayController;
	public Location						currentGPSLocationOfPhone	= null;
	protected LocationManager			locationManager				= null;
	protected IRemoteStopClockService	messageService;
	private static final String			TAG							= CurrentRunMapControllerImpl.class.getName();
	protected LocationProvider			provider;
	private String						elapsedTime					= "0";

	protected IDBHelper					dbHelper;

	protected List<Location>			path						= new ArrayList<Location>();

	private CurrentRunMapOverlay		googleMapOverlay;
	private DetailsOverlay				detailsOverlay;

	public CurrentRunMapControllerImpl(CurrentRunMap mapOfJog) {
		this.mapOfJogActivity = mapOfJog;
		this.dbHelper = new DBHelperImpl();
		this.locationManager = (LocationManager) mapOfJog.getSystemService(Context.LOCATION_SERVICE);
		Location location = locationManager.getLastKnownLocation(ActivityID.GPS_PROVIDER);
		this.setCurrentGPSLocationOfPhone(location);
	}

	private void updateStopwatch() {
		elapsedTime = RemoteStopClockServiceInterface.getInstance().getElapsedTime();
		detailsOverlay.setTime(elapsedTime);
		if (RemoteStopClockServiceInterface.getInstance().isClockRunning()) {
			Message nextUpdateMsg = Message.obtain(currentRunMapHandler, ActivityID.UPDATESTOPCLOCK);
			currentRunMapHandler.sendMessageDelayed(nextUpdateMsg, 85);
		}
	}

	protected Handler	currentRunMapHandler	= new Handler()
												{
													public void handleMessage(Message msg) {
														switch (msg.what) {
															case ActivityID.UPDATESTOPCLOCK:
																mapOfJogView.invalidateMapView();
																updateStopwatch();
																break;
															case ActivityID.STARTTRACKER:
																startTrackingRoute();
																break;
															case ActivityID.STOPTRACKER:
																stopTrackingRoute();
																break;
															case ActivityID.LOCATION_UPDATE:
																Location newLoc = (Location) msg.obj;
																Log.w(TAG, "Got LOCATION_UPDATE in currentRunMapController "
																		+ newLoc.getLatitude() + ", " + newLoc.getLongitude());
																updateRunningPathWithLocation(newLoc);
																break;
														}
														super.handleMessage(msg);
													}
												};

	public Handler getUpdateHandler() {
		return currentRunMapHandler;
	}

	private boolean	serviceRunning;

	public void startTrackingRoute() {
		serviceRunning = true;
	}

	public void stopTrackingRoute() {
		serviceRunning = false;
	}

	public void createMapOfJogView(MapView mapView) {
		this.mapOfJogView = new CurrentRunMapView(mapOfJogActivity, this, mapView);
		this.mapViewController = mapView.getController();

		//this.overlayController = mapView.createOverlayController();

		this.googleMapOverlay = new CurrentRunMapOverlay(this.mapOfJogActivity, mapView, BitmapFactory.decodeResource(
				this.mapOfJogActivity.getResources(), R.drawable.map_start_point), BitmapFactory.decodeResource(
				this.mapOfJogActivity.getResources(), R.drawable.map_stop_point));

		this.detailsOverlay = new DetailsOverlay(this.mapOfJogActivity, BitmapFactory.decodeResource(this.mapOfJogActivity
				.getResources(), R.drawable.dial));

		mapView.getOverlays().add(googleMapOverlay);
		mapView.getOverlays().add(detailsOverlay);
		//overlayController.add(googleMapOverlay, true);
		//overlayController.add(detailsOverlay, false);

	}

	public void gotoCurrentGPSPosition() {

		GeoPoint point = new GeoPoint((int) (this.currentGPSLocationOfPhone.getLatitude() * 1000000),
				(int) (this.currentGPSLocationOfPhone.getLongitude() * 1000000));

		Log.w("jjm", "mapview set point " + point.getLatitudeE6() + ", " + point.getLongitudeE6());
		
		mapViewController.animateTo(point);
		mapViewController.setZoom(18);
		mapOfJogView.invalidateMapView();

	}

	// private Point getMapPointFromLocationList(int pos) {
	// String[] loc = locations[pos][1].split(",");
	//
	// double lat = Double.parseDouble(loc[1]);
	// double lon = Double.parseDouble(loc[0]);
	//
	// return new Point((int) (lat * 1000000), (int) (lon * 1000000));
	// }

	public void zoomTo(int zoomLevel) {
		this.mapViewController.setZoom(zoomLevel);
	}

	public boolean onKeyDown(int keyCode, KeyEvent event) {
		boolean consumed = true;

		switch (keyCode) {
			case KeyEvent.KEYCODE_I:
				mapViewController.setZoom(mapOfJogView.getZoomLevel() + 1);
				break;
			case KeyEvent.KEYCODE_O:
				mapViewController.setZoom(mapOfJogView.getZoomLevel() - 1);
				break;
			case KeyEvent.KEYCODE_V:
				stopTrackingRoute();
				break;
			case KeyEvent.KEYCODE_B:
				startTrackingRoute();
				break;
			case KeyEvent.KEYCODE_N:
				draw3Point();
				break;
			case KeyEvent.KEYCODE_M:
				draw4Point();
				break;
			case KeyEvent.KEYCODE_L:
				drawPoints();
				break;
			case KeyEvent.KEYCODE_S:
				mapOfJogView.toggleSatellite();
				break;
			case KeyEvent.KEYCODE_BACK:
				stopPlottingJog();
				mapOfJogActivity.finish();
				break;
			default:
				consumed = false;
				break;
		}

		return consumed;
	}

	private void stopPlottingJog() {

	}

	public void draw1Point() {
		addPoint(55846809, -4229920);
	}

	public void draw2Point() {
		addPoint(55846809, -4231200);
	}

	public void draw3Point() {
		addPoint(55851200, -4236400);
	}

	public void draw4Point() {
		addPoint(55851000, -4236800);
	}

	private boolean addPoint(double latitude, double longitude) {
		Location pointLocation = new Location("location");
		pointLocation.setLatitude(latitude);
		pointLocation.setLongitude(longitude);
		this.googleMapOverlay.addLocationToPath(pointLocation);
		mapOfJogView.invalidateMapView();
		return true;
	}

	public void drawPoints() {
		draw1Point();
		draw2Point();
		draw3Point();
		draw4Point();
	}

	public void updateRunningPath() {
		if (this.currentGPSLocationOfPhone != null) {
			Log.v(TAG, "Updating a jogging a current jogging route.");
			Location location = locationManager.getLastKnownLocation(ActivityID.GPS_PROVIDER);
			Log.i(TAG, "Updating longitude: " + location.getLongitude() + ", latitude: " + location.getLatitude());
			this.setCurrentGPSLocationOfPhone(location);

			Location pointLocation = new Location("location");
			pointLocation.setLatitude(this.currentGPSLocationOfPhone.getLatitude() * 1000000);
			pointLocation.setLongitude(this.currentGPSLocationOfPhone.getLongitude() * 1000000);
			this.googleMapOverlay.addLocationToPath(pointLocation);
			gotoCurrentGPSPosition();
		}
	}

	public void updateRunningPathWithLocation(Location location) {
		//if (this.currentGPSLocationOfPhone != null) {
			this.setCurrentGPSLocationOfPhone(location);

			Location pointLocation = new Location("location");
			pointLocation.setLatitude(this.currentGPSLocationOfPhone.getLatitude() * 1000000);
			pointLocation.setLongitude(this.currentGPSLocationOfPhone.getLongitude() * 1000000);
			this.googleMapOverlay.addLocationToPath(pointLocation);
			gotoCurrentGPSPosition();
		//}
	}

	public void setCurrentGPSLocationOfPhone(Location currentLocation) {
		this.currentGPSLocationOfPhone = currentLocation;
	}

	public boolean getIfServiceIsRunning() {
		return serviceRunning;
	}

	public void setServiceRunning(boolean serviceisrunning) {
		this.serviceRunning = serviceisrunning;
	}

	public void onResume() {
		updateStopwatch();
		/* Add all existing points from the current jog to the displayed route. */
		Jog currentJog = RemoteStopClockServiceInterface.getInstance().getCurrentJog();
		if (currentJog != null) {
			googleMapOverlay.clearPath();

			Map<Long, Location> locations = currentJog.getlocationsAndTimes();
			Iterator<Map.Entry<Long, Location>> it = locations.entrySet().iterator();
			while (it.hasNext()) {
				Location loc = it.next().getValue();
				loc.setLatitude(loc.getLatitude() / 1000000);
				loc.setLongitude(loc.getLongitude() / 1000000);
				updateRunningPathWithLocation(loc);
			}
		}

	}

}
